package dungeonElements;

import java.math.BigDecimal;

import org.junit.*;
import static org.junit.Assert.*;

import temperature.Temperature;
import dungeonTools.Direction;

/**
 * @author Tom Jacobs & Ewoud De Moor
 * @version 3.0
 */
public class RockTest {

	public static Rock rock;
	
	@Before
	public void setUp() throws Exception {
		rock = new Rock();
	}

	@After
	public void tearDown() throws Exception {
		if(!rock.isTerminated()){
			assertTrue(rock.getHumidity() == 0.0d);
			for(Direction direction : Direction.values())
				assertTrue(rock.getBorder(direction) instanceof Wall);
			assertTrue(rock.canHaveAsTemperature(rock.getTemperature()));
		}
	}

	
	@Test
	public void newRock() {
		Rock newRock = new Rock();
		assertEquals(Temperature.CELSIUS_0, newRock.getTemperature());
		assertEquals(0.0d, newRock.getHumidity(), 0.0000008d);
		for( Direction testDirection : Direction.values() ){
			assertTrue(newRock.getBorder(testDirection) instanceof Wall);
		}
		assertFalse(newRock.isSlippery());
		assertFalse(newRock.isTerminated());
	}	
	
	@Test
	public void terminateTest() {
		rock.terminate();
		for( Direction testDirection : Direction.values() ){
			assertTrue(rock.getBorder(testDirection) == null);
		}
		assertTrue(rock.isTerminated());
	}	

	@Test (expected = IllegalArgumentException.class)
	public void setTemparture_UnsupportedOperation() {
		rock.setTemperature(new Temperature(BigDecimal.TEN));
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void testSetBorder_toNull() {
		rock.setBorder(null, Direction.NORTH);
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void testSetBorder_toDoor() {
		Square square = new NormalSquare();
		square.buildDoor(Direction.SOUTH);
		Border border = square.getBorder(Direction.SOUTH);
		rock.setBorder(border, Direction.NORTH);
	}
	
	@Test
	public void testSetBorder_toWall() {
		Square square = new NormalSquare();
		Border border = square.getBorder(Direction.SOUTH);
		rock.setBorder(border, Direction.NORTH);
		assertEquals(border, rock.getBorder(Direction.NORTH));
		assertEquals(rock, border.getSquareInDirection(Direction.NORTH.getOppositeDirection()));
	}

	@Test (expected = IllegalArgumentException.class)
	public void testBreakBorder() {
		rock.breakBorder(Direction.EAST);
	}

	@Test (expected = IllegalArgumentException.class)
	public void testBuildDoor() {
		rock.buildDoor(Direction.EAST);
	}
	
	@Test 
	public void testBuildWall() {
		rock.buildWall(Direction.EAST);
		assertTrue(rock.getBorder(Direction.EAST) instanceof Wall);
		assertTrue(rock.hasProperBorders());
	}
	
	@Test //(expected = AssertionError.class)
	public void testSetHumidity() {
		assertEquals(0.0d, rock.getHumidity(), 0.0000008d);
		assertTrue(rock.canHaveAsHumidity(0.0d));
		assertFalse(rock.canHaveAsHumidity(20.0d));
//		rock.setHumidity();
	}
	
	@Test 
	public void testSetTemperature_validNoBorderingSquares() {
		assertTrue(rock.canHaveAsTemperature(rock.getTemperature()));
		assertEquals(Temperature.CELSIUS_0, rock.getTemperature());
		assertTrue(rock.canHaveAsTemperature(Temperature.CELSIUS_0));
		assertEquals(Temperature.CELSIUS_0, rock.getAverageTemperatureOfBorderingSquares());
		rock.setTemperature();
		assertTrue(rock.canHaveAsTemperature(rock.getTemperature()));
		assertEquals(Temperature.CELSIUS_0, rock.getTemperature());
		assertTrue(rock.canHaveAsTemperature(Temperature.CELSIUS_0));
		assertEquals(Temperature.CELSIUS_0, rock.getAverageTemperatureOfBorderingSquares());
	}
	
	@Test 
	public void testSetTemperature_validWithBorderingSquares() {
		Temperature temperature = new Temperature(BigDecimal.valueOf(50));
		Temperature averageTemperature = new Temperature(BigDecimal.valueOf(25));
		Square square = new NormalSquare(temperature,10.0d,true,true,true,true,true,true);
		Square square2 = new NormalSquare(Temperature.CELSIUS_0,90.0d,true,true,true,true,true,true);
		Border border = square.getBorder(Direction.NORTH);
		Border border2 = square2.getBorder(Direction.EAST);
		rock.setBorder(border, Direction.SOUTH);
		assertTrue(rock.canHaveAsTemperature(rock.getTemperature()));
		assertEquals(temperature, rock.getTemperature());
		assertTrue(rock.canHaveAsTemperature(temperature));
		assertEquals(temperature, rock.getAverageTemperatureOfBorderingSquares());
		rock.setBorder(border2, Direction.WEST);
		assertTrue(rock.canHaveAsTemperature(rock.getTemperature()));
		assertEquals(averageTemperature, rock.getTemperature());
		assertTrue(rock.canHaveAsTemperature(averageTemperature));
		assertEquals(averageTemperature, rock.getAverageTemperatureOfBorderingSquares());
	}
	
	@Test 
	public void testSetTemperature_changeTemperatureOfBorderingSquares() {
		Temperature temperature = new Temperature(BigDecimal.valueOf(100));
		Temperature averageTemperature = new Temperature(BigDecimal.valueOf(50));
		Temperature newTemperature = new Temperature(BigDecimal.valueOf(50));
		Temperature newAverageTemperature = new Temperature(BigDecimal.valueOf(25));
		Square square = new NormalSquare(temperature,10.0d,true,true,true,true,true,true);
		Square square2 = new NormalSquare(Temperature.CELSIUS_0,90.0d,true,true,true,true,true,true);
		Rock rock2 = new Rock();
		Border border = square.getBorder(Direction.NORTH);
		rock.setBorder(border, Direction.SOUTH);
		Border border2 = square2.getBorder(Direction.EAST);
		rock.setBorder(border2, Direction.WEST);
		Border border3 = rock.getBorder(Direction.CEILING);
		rock2.setBorder(border3, Direction.FLOOR);
		assertTrue(rock.canHaveAsTemperature(rock.getTemperature()));
		assertEquals(averageTemperature, rock.getTemperature());
		assertTrue(rock.canHaveAsTemperature(averageTemperature));
		assertEquals(averageTemperature, rock.getAverageTemperatureOfBorderingSquares());
		assertTrue(rock2.canHaveAsTemperature(rock2.getTemperature()));
		assertEquals(averageTemperature, rock2.getTemperature());
		assertTrue(rock2.canHaveAsTemperature(averageTemperature));
		assertEquals(averageTemperature, rock2.getAverageTemperatureOfBorderingSquares());
		square.setTemperature(newTemperature);
		assertTrue(rock.canHaveAsTemperature(rock.getTemperature()));
		assertEquals(newAverageTemperature, rock.getTemperature());
		assertTrue(rock.canHaveAsTemperature(newAverageTemperature));
		assertEquals(newAverageTemperature, rock.getAverageTemperatureOfBorderingSquares());
		assertTrue(rock2.canHaveAsTemperature(rock2.getTemperature()));
		assertEquals(newAverageTemperature, rock2.getTemperature());
		assertTrue(rock2.canHaveAsTemperature(newAverageTemperature));
		assertEquals(newAverageTemperature, rock2.getAverageTemperatureOfBorderingSquares());
	}
	
	@Test 
	public void testSetTemperature_validWithMoreBorderingSquares() {
		Temperature temperature = new Temperature(BigDecimal.valueOf(50));
		Temperature temperature2 = new Temperature(BigDecimal.valueOf(-100));
		Temperature averageTemperature = new Temperature(BigDecimal.valueOf(25));
		Temperature otherAverageTemperature = new Temperature(BigDecimal.valueOf(-50));
		Temperature newAverageTemperature = new Temperature(BigDecimal.valueOf(11.111111111111111));
		Square squareA = new NormalSquare(temperature,10.0d,true,true,true,true,true,true);
		Square squareB = new NormalSquare(Temperature.CELSIUS_0,90.0d,true,true,true,true,true,true);
		Square squareC = new NormalSquare(temperature,10.0d,true,true,true,true,true,true);
		Square squareD = new NormalSquare(Temperature.CELSIUS_0,90.0d,true,true,true,true,true,true);
		Square squareE = new NormalSquare(averageTemperature,10.0d,true,true,true,true,true,true);
		Square squareF = new NormalSquare(temperature2,90.0d,true,true,true,true,true,true);
		Rock rock1 = new Rock();
		Rock rock2 = new Rock();
		Rock rock3 = new Rock();
		Rock rock4 = new Rock();
		Rock rock5 = new Rock();
		Rock rock6 = new Rock();
		Border border1 = rock1.getBorder(Direction.EAST);
		rock2.setBorder(border1, Direction.WEST);
		Border border2 = rock2.getBorder(Direction.EAST);
		rock3.setBorder(border2, Direction.WEST);
		Border border3 = rock3.getBorder(Direction.SOUTH);
		rock4.setBorder(border3, Direction.NORTH);
		Border border4 = rock4.getBorder(Direction.EAST);
		rock5.setBorder(border4, Direction.WEST);
		Border border5 = rock1.getBorder(Direction.WEST);
		squareA.setBorder(border5, Direction.EAST);
		Border border6 = rock2.getBorder(Direction.CEILING);
		squareB.setBorder(border6, Direction.FLOOR);
		Border border7 = rock4.getBorder(Direction.SOUTH);
		squareC.setBorder(border7, Direction.NORTH);
		Border border8 = rock5.getBorder(Direction.EAST);
		squareD.setBorder(border8, Direction.WEST);
		Border border9 = rock6.getBorder(Direction.NORTH);
		squareD.setBorder(border9, Direction.SOUTH);
		Border border10 = rock6.getBorder(Direction.FLOOR);
		squareF.setBorder(border10, Direction.CEILING);
		Border border11 = rock3.getBorder(Direction.EAST);
		squareE.setBorder(border11, Direction.WEST);
		Border border12 = rock5.getBorder(Direction.NORTH);
		squareE.setBorder(border12, Direction.SOUTH);
		assertTrue(rock.canHaveAsTemperature(rock.getTemperature()));
		assertTrue(rock1.canHaveAsTemperature(rock1.getTemperature()));
		assertTrue(rock2.canHaveAsTemperature(rock2.getTemperature()));
		assertTrue(rock3.canHaveAsTemperature(rock3.getTemperature()));
		assertTrue(rock4.canHaveAsTemperature(rock4.getTemperature()));
		assertTrue(rock5.canHaveAsTemperature(rock5.getTemperature()));
		assertTrue(rock6.canHaveAsTemperature(rock6.getTemperature()));
		assertEquals(Temperature.CELSIUS_0, rock.getTemperature());
		assertEquals(averageTemperature, rock1.getTemperature());
		assertEquals(averageTemperature, rock2.getTemperature());
		assertEquals(averageTemperature, rock3.getTemperature());
		assertEquals(averageTemperature, rock4.getTemperature());
		assertEquals(averageTemperature, rock5.getTemperature());
		assertEquals(otherAverageTemperature, rock6.getTemperature());
		rock1.setTemperature();
		rock5.setTemperature();
		rock6.setTemperature();
		assertTrue(rock.canHaveAsTemperature(rock.getTemperature()));
		assertTrue(rock1.canHaveAsTemperature(rock1.getTemperature()));
		assertTrue(rock2.canHaveAsTemperature(rock2.getTemperature()));
		assertTrue(rock3.canHaveAsTemperature(rock3.getTemperature()));
		assertTrue(rock4.canHaveAsTemperature(rock4.getTemperature()));
		assertTrue(rock5.canHaveAsTemperature(rock5.getTemperature()));
		assertTrue(rock6.canHaveAsTemperature(rock6.getTemperature()));
		assertEquals(Temperature.CELSIUS_0, rock.getTemperature());
		assertEquals(averageTemperature, rock1.getTemperature());
		assertEquals(averageTemperature, rock2.getTemperature());
		assertEquals(averageTemperature, rock3.getTemperature());
		assertEquals(averageTemperature, rock4.getTemperature());
		assertEquals(averageTemperature, rock5.getTemperature());
		assertEquals(otherAverageTemperature, rock6.getTemperature());
		Border border13 = rock.getBorder(Direction.WEST);
		squareC.setBorder(border13, Direction.EAST);
		Border border14 = rock.getBorder(Direction.NORTH);
		rock5.setBorder(border14, Direction.SOUTH);
		Border border15 = rock.getBorder(Direction.EAST);
		rock6.setBorder(border15, Direction.WEST);
		assertTrue(rock.canHaveAsTemperature(rock.getTemperature()));
		assertTrue(rock1.canHaveAsTemperature(rock1.getTemperature()));
		assertTrue(rock2.canHaveAsTemperature(rock2.getTemperature()));
		assertTrue(rock3.canHaveAsTemperature(rock3.getTemperature()));
		assertTrue(rock4.canHaveAsTemperature(rock4.getTemperature()));
		assertTrue(rock5.canHaveAsTemperature(rock5.getTemperature()));
		assertTrue(rock6.canHaveAsTemperature(rock6.getTemperature()));
		assertEquals(newAverageTemperature, rock.getTemperature());
		assertEquals(newAverageTemperature, rock1.getTemperature());
		assertEquals(newAverageTemperature, rock2.getTemperature());
		assertEquals(newAverageTemperature, rock3.getTemperature());
		assertEquals(newAverageTemperature, rock4.getTemperature());
		assertEquals(newAverageTemperature, rock5.getTemperature());
		assertEquals(newAverageTemperature, rock6.getTemperature());
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void testSetTemperature_InvalidValues() {
		assertTrue(rock.canHaveAsTemperature(rock.getTemperature()));
		Temperature temperature = new Temperature(BigDecimal.valueOf(500));
		assertFalse(rock.canHaveAsTemperature(temperature));
		Temperature temperature2 = new Temperature(BigDecimal.valueOf(1));
		assertFalse(rock.canHaveAsTemperature(temperature2));
		Temperature temperature3 = new Temperature(BigDecimal.valueOf(-1));
		assertFalse(rock.canHaveAsTemperature(temperature3));
		rock.setTemperature();
		assertTrue(rock.canHaveAsTemperature(rock.getTemperature()));
		assertFalse(rock.canHaveAsTemperature(temperature));
		assertFalse(rock.canHaveAsTemperature(temperature2));
		assertFalse(rock.canHaveAsTemperature(temperature3));
		rock.setTemperature(temperature);
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void testSetTemperature_invalidWithBorderingSquares() {
		Temperature temperature = new Temperature(BigDecimal.valueOf(50));
		Temperature temperature2 = new Temperature(BigDecimal.valueOf(500));
		Temperature temperature3 = new Temperature(BigDecimal.valueOf(-10));
		Square square = new NormalSquare(temperature,10.0d,true,true,true,true,true,true);
		Square square2 = new NormalSquare(Temperature.CELSIUS_0,90.0d,true,true,true,true,true,true);
		Border border = square.getBorder(Direction.NORTH);
		Border border2 = square2.getBorder(Direction.EAST);
		rock.setBorder(border, Direction.SOUTH);
		assertTrue(rock.canHaveAsTemperature(rock.getTemperature()));
		assertFalse(rock.canHaveAsTemperature(temperature2));
		assertFalse(rock.canHaveAsTemperature(temperature3));
		rock.setBorder(border2, Direction.WEST);
		assertTrue(rock.canHaveAsTemperature(rock.getTemperature()));
		assertFalse(rock.canHaveAsTemperature(temperature2));
		assertFalse(rock.canHaveAsTemperature(temperature3));
		rock.setTemperature(temperature3);
	}
	
}
